package com.mxx.common.netty.ws;

import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelMatchers;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @Auther: Mr. Zeng
 * @Date: 2020/6/29 17:05
 * @Description: 暂无描述
 */
@Slf4j
public final class NettyChannelSupervise {
    public static boolean LOGO = true;
    private static DefaultChannelGroup GLOBAL_GROUP = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private static ConcurrentMap<String, ChannelId> CHANNEL_MAP = new ConcurrentHashMap<>();

    /**
     * 添加通道
     *
     * @param channel
     */
    public static void addChannel(Channel channel) {
        GLOBAL_GROUP.add(channel);
        CHANNEL_MAP.put(channel.id().asShortText(), channel.id());
    }

    /**
     * 移除通道
     *
     * @param channel
     */
    public static void removeChannel(Channel channel) {
        GLOBAL_GROUP.remove(channel);
        CHANNEL_MAP.remove(channel.id().asShortText());
    }

    /**
     * 移除通道
     *
     * @param channelShortId
     */
    public static void removeChannel(String channelShortId) {
        ChannelId channelId = CHANNEL_MAP.remove(channelShortId);
        if (channelId != null) {
            Channel channel = GLOBAL_GROUP.find(channelId);
            GLOBAL_GROUP.remove(channel);
        }
    }

    /**
     * 获取通道
     *
     * @param id
     * @return
     */

    public static Channel findChannel(String id) {
        ChannelId channelId = CHANNEL_MAP.get(id);
        if (channelId != null) {
            return GLOBAL_GROUP.find(channelId);
        }
        log.info("findChannel(channelId) . channelId [{}] not found", id);
        return null;
    }

    /**
     * 发送消息给自己
     *
     * @param channelId
     * @param textWebSocketFrame
     * @return
     */

    public static boolean sendOfChannel(String channelId, TextWebSocketFrame textWebSocketFrame) {
        Channel channel = findChannel(channelId);
        if (channel != null) {
            log("[{}] sendOfChannel --> [{}] ", channel.id().asShortText(), textWebSocketFrame.text());
            channel.writeAndFlush(textWebSocketFrame);
            return true;
        }
        log.info("sendSelf(channelId,textWebSocketFrame) . channel [{}] not found", channelId);
        return false;
    }

    /**
     * 发送消息给自己
     *
     * @param collectionChannelId
     * @param textWebSocketFrame
     * @return
     */

    public static int sendOfChannel(Collection<String> collectionChannelId, TextWebSocketFrame textWebSocketFrame) {
        int count = 0;
        if (!collectionChannelId.isEmpty()) {
            Iterator<String> iterator = collectionChannelId.iterator();
            while (iterator.hasNext()) {
                String channelId = iterator.next();
                boolean flag = NettyChannelSupervise.sendOfChannel(channelId, textWebSocketFrame);
                if (flag){
                    count ++;
                }
            }

        }
        return  count;
    }

    /**
     * 发送消息给自己
     *
     * @param channel
     * @param textWebSocketFrame
     * @return
     */

    public static boolean sendOfChannel(Channel channel, TextWebSocketFrame textWebSocketFrame) {
        ChannelId channelId = channel.id();
        String channelSortId = channelId.asShortText();
        CHANNEL_MAP.put(channelSortId, channelId);
        GLOBAL_GROUP.add(channel);

        log("[{}] sendOfChannel --> [{}] ", channel.id().asShortText(), textWebSocketFrame.text());
        channel.writeAndFlush(textWebSocketFrame);

        return false;
    }


    /**
     * 广播消息
     *
     * @param domainChannel      当前通道，会忽略当前通道
     * @param textWebSocketFrame
     */
    public static void sendAll(Channel domainChannel, TextWebSocketFrame textWebSocketFrame) {
        log("[{}] sendAll --> [{}] ", domainChannel.id().asShortText(), textWebSocketFrame.text());
        GLOBAL_GROUP.writeAndFlush(textWebSocketFrame, ChannelMatchers.isNot(domainChannel));
    }

    /**
     * 广播消息
     *
     * @param domainChannelId    当前通道ID，会忽略当前通道
     * @param textWebSocketFrame
     */
    public static void sendAll(String domainChannelId, TextWebSocketFrame textWebSocketFrame) {
        Channel channel = findChannel(domainChannelId);
        if (channel == null) {
            log.error("sendAll(textWebSocketFrame,domainChannelId) . channel [{}] not found", domainChannelId);
        }
        log("[{}] sendAll --> [{}] ", domainChannelId, textWebSocketFrame.text());
        GLOBAL_GROUP.writeAndFlush(textWebSocketFrame, ChannelMatchers.isNot(channel));
    }

    /**
     * 广播消息
     *
     * @param textWebSocketFrame
     */
    public static void sendAll(TextWebSocketFrame textWebSocketFrame) {
        GLOBAL_GROUP.writeAndFlush(textWebSocketFrame);
    }

    public static Iterator<Channel> iterator() {
        return GLOBAL_GROUP.iterator();
    }

    private static void log(String info, Object... obj) {
        log.info(info, obj);
    }
}
